namespace AopDotNetAddIn
{
	using System;
	using System.Collections ;
	using System.IO;
	using System.Xml .Serialization;
	using Microsoft.Office.Core;
	using Extensibility;
	using System.Runtime.InteropServices;
	using EnvDTE;
	using System.Xml;
	using System.Windows.Forms;

	using System.CodeDom .Compiler ;
	using System.CodeDom ;
	using Microsoft.CSharp ;
	using Microsoft.VisualBasic ;
	using System.Reflection ;
	using VSLangProj;
	using VSLangProj2 ;
	
	using AopDotNet;
	using AopDotNet.CodeModelXMLTreeBuilder;
	using AopDotNet.JoinPointSearchEngine;
	using AopDotNet.AspectWeaver;
	using AopDotNet.Editor ;

	#region Read me for Add-in installation and setup information.
	// When run, the Add-in wizard prepared the registry for the Add-in.
	// At a later time, if the Add-in becomes unavailable for reasons such as:
	//   1) You moved this project to a computer other than which is was originally created on.
	//   2) You chose 'Yes' when presented with a message asking if you wish to remove the Add-in.
	//   3) Registry corruption.
	// you will need to re-register the Add-in by building the MyAddin21Setup project 
	// by right clicking the project in the Solution Explorer, then choosing install.
	#endregion
	
	/// <summary>
	///   The object for implementing an Add-in.
	/// </summary>
	/// <seealso class='IDTExtensibility2' />
	[GuidAttribute("26BB6855-2D1B-4974-9215-D2A2372B1C9B"), ProgId("AopDotNetAddIn.Connect")]
	public class Connect : Object, Extensibility.IDTExtensibility2,IDTCommandTarget ,IDTWizard
	{
		/// <summary>
		///		Implements the constructor for the Add-in object.
		///		Place your initialization code within this method.
		/// </summary>
		public Connect()
		{
			IsWeaving=false;
		bAddInBuild=false;
		}

		/// <summary>
		///      Implements the OnConnection method of the IDTExtensibility2 interface.
		///      Receives notification that the Add-in is being loaded.
		/// </summary>
		/// <param term='application'>
		///      Root object of the host application.
		/// </param>
		/// <param term='connectMode'>
		///      Describes how the Add-in is being loaded.
		/// </param>
		/// <param term='addInInst'>
		///      Object representing this Add-in.
		/// </param>
		/// <seealso class='IDTExtensibility2' />
		public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom)
		{
			applicationObject = (_DTE)application;
			addInInstance = (AddIn)addInInst;
			if ((connectMode == Extensibility.ext_ConnectMode.ext_cm_Startup)
				|| (connectMode == Extensibility.ext_ConnectMode.ext_cm_AfterStartup))
			{
				object []contextGUIDS = new object[] { };
				Commands commands = applicationObject.Commands;
                _CommandBars commandBars = (_CommandBars)applicationObject.CommandBars;
				Command cmdWeave;
				Command cmdUnweave;

				// When run, the Add-in wizard prepared the registry for the Add-in.
				// At a later time, the Add-in or its commands may become unavailable for reasons such as:
				//   1) You moved this project to a computer other than which is was originally created on.
				//   2) You chose 'Yes' when presented with a message asking if you wish to remove the Add-in.
				//   3) You add new commands or modify commands already defined.
				// You will need to re-register the Add-in by building the TextUtilSetup project,
				// right-clicking the project in the Solution Explorer, and then choosing install.
				// Alternatively, you could execute the ReCreateCommands.reg file the Add-in Wizard generated in
				// the project directory, or run 'devenv /setup' from a command prompt.
				try
				{
					/*	CommandBar commandBar2 = (CommandBar)commandBars["MenuBar"];
						Microsoft.Office .Core .CommandBarControl com3=commandBar2.Controls ["Build"];
						Command nmd = applicationObject.Commands.AddNamedCommand (addInInstance
							, "Aspects"
							, "&Weave"
							, "Weave Aspects"
							, true, 59,  ref contextGUIDS,(int)vsCommandStatus.vsCommandStatusSupported+(int)vsCommandStatus.vsCommandStatusEnabled);
						nmd.AddControl (com3,1);
	*/					
					/*	try
						{
							cmd=applicationObject.Commands.Item ("AopDotNetAddIn.Connect.WeaveAspects", -1);
							cmd.Delete ();
							if (1==1)
								return;
						}
						catch(Exception ecx)
						{
							string ecxM=ecx.Message ;
						}*/
					
					cmdWeave = applicationObject.Commands.AddNamedCommand (addInInstance
						, "WeaveAspects"
						, "&Weave and Run"
						, "Weave"
						, true, 59,  ref contextGUIDS,(int)vsCommandStatus.vsCommandStatusSupported+(int)vsCommandStatus.vsCommandStatusEnabled);
					/****/
					contextGUIDS = new object[] { };
					cmdUnweave= applicationObject.Commands.AddNamedCommand (addInInstance
						, "UnWeaveAspects"
						, "&UnWeave"
						, "UnWeave"
						, true, 59,  ref contextGUIDS,(int)vsCommandStatus.vsCommandStatusSupported+(int)vsCommandStatus.vsCommandStatusEnabled);
					
					 /****/
					CommandBar commandBar = (CommandBar)commandBars["Build"];
                    CommandBarControl commandBarControlWeave = (CommandBarControl)cmdWeave.AddControl(commandBar, 1);
					/***/
                    CommandBarControl commandBarControlUnWeave = (CommandBarControl)cmdUnweave.AddControl(commandBar, 2);
					/***/

					CommandBar commandBar2 = (CommandBar)commandBars["MenuBar"];
					IEnumerator en=commandBar2.Controls .GetEnumerator ();
					while (en.MoveNext ())
					{
						CommandBarControl com=(CommandBarControl)en.Current;
						if ( com.Caption =="&Build")
						{
							CommandBar commandBar3=((CommandBarPopup) com).CommandBar ;
							cmdWeave.AddControl (commandBar3,3);
							/***/
							cmdUnweave.AddControl (commandBar3,4);
							/***/
							break;
						}
					}
					
					
				}
				catch(System.Exception e)
				{
					string strM=e.Message ;
				}
			
				
			}
			
			solutionEvents =( EnvDTE.SolutionEvents)applicationObject.Events.SolutionEvents ;
			solutionEvents.Opened += new _dispSolutionEvents_OpenedEventHandler (this.onSolutionOpend);
			


			buildEvents =(EnvDTE.BuildEvents ) applicationObject.Events.BuildEvents;
			buildEvents.OnBuildProjConfigDone  += new _dispBuildEvents_OnBuildProjConfigDoneEventHandler(this.OnBuildProjConfigDone);
			buildEvents.OnBuildDone +=new _dispBuildEvents_OnBuildDoneEventHandler(buildEvents_OnBuildDone);
			//buildEvents.OnBuildProjConfigBegin  += new _dispBuildEvents_OnBuildProjConfigBeginEventHandler(this.OnBuildProjConfigBegin);


			//applicationObject.ItemOperations .
		}
		public void QueryStatus(string commandName, EnvDTE.vsCommandStatusTextWanted neededText, ref EnvDTE.vsCommandStatus status, ref object commandText)
		{
			if(neededText == EnvDTE.vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
			{
				if(commandName == "AopDotNetAddIn.Connect.WeaveAspects")
				{
					status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported|vsCommandStatus.vsCommandStatusEnabled;
				}
				if(commandName == "AopDotNetAddIn.Connect.UnWeaveAspects")
				{
					status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported|vsCommandStatus.vsCommandStatusEnabled;
				}
			}
		}
		
		public void onSolutionOpend()
		{
			buildEvents =(EnvDTE.BuildEvents ) applicationObject.Events.BuildEvents;
			buildEvents.OnBuildProjConfigDone   += new _dispBuildEvents_OnBuildProjConfigDoneEventHandler (this.OnBuildProjConfigDone );
			//buildEvents.OnBuildDone += new _dispBuildEvents_OnBuildDoneEventHandler (this.OnBuildDone);
	
		}

		/*public void OnBuildDone(vsBuildScope scope,vsBuildAction action)
		{
			string s;
			s="fdfDF";
		}*/
		
		/// <summary>
		///     Implements the OnDisconnection method of the IDTExtensibility2 interface.
		///     Receives notification that the Add-in is being unloaded.
		/// </summary>
		/// <param term='disconnectMode'>
		///      Describes how the Add-in is being unloaded.
		/// </param>
		/// <param term='custom'>
		///      Array of parameters that are host application specific.
		/// </param>
		/// <seealso class='IDTExtensibility2' />
		public void OnDisconnection(Extensibility.ext_DisconnectMode disconnectMode, ref System.Array custom)
		{
		}

		/// <summary>
		///      Implements the OnAddInsUpdate method of the IDTExtensibility2 interface.
		///      Receives notification that the collection of Add-ins has changed.
		/// </summary>
		/// <param term='custom'>
		///      Array of parameters that are host application specific.
		/// </param>
		/// <seealso class='IDTExtensibility2' />
		public void OnAddInsUpdate(ref System.Array custom)
		{
		}

		/// <summary>
		///      Implements the OnStartupComplete method of the IDTExtensibility2 interface.
		///      Receives notification that the host application has completed loading.
		/// </summary>
		/// <param term='custom'>
		///      Array of parameters that are host application specific.
		/// </param>
		/// <seealso class='IDTExtensibility2' />
		public void OnStartupComplete(ref System.Array custom)
		{
		}

		/*public void OnBuildProjConfigBegin(string szProject, string ProjectConfig, 
			string Platform, string SolutionConfig)
		{
			string x="dfgdfg";
			x=x+"FFF";
		}*/
		public void OnBuildProjConfigDone(string szProject, string ProjectConfig, 
			string Platform, string SolutionConfig,bool Success)
		{
		
			if (IsWeaving)  /*Error Handling*/ //errors may be from the weaving
			{
				IsWeaving=false;
				applicationObject.UndoContext.SetAborted();
				applicationObject.UndoContext.Close ();
				if (Success==false)
					MessageBox.Show ("Error Compiling the weaved code","AopDotNetAddIn");
				
			}
		}

		/// <summary>
		///      Implements the OnBeginShutdown method of the IDTExtensibility2 interface.
		///      Receives notification that the host application is being unloaded.
		/// </summary>
		/// <param term='custom'>
		///      Array of parameters that are host application specific.
		/// </param>
		/// <seealso class='IDTExtensibility2' />
		public void OnBeginShutdown(ref System.Array custom)
		{
		}
		/// <summary>
		///      Implements the Exec method of the IDTCommandTarget interface.
		///      This is called when the command is invoked.
		/// </summary>
		/// <param term='commandName'>
		///		The name of the command to execute.
		/// </param>
		/// <param term='executeOption'>
		///		Describes how the command should be run.
		/// </param>
		/// <param term='varIn'>
		///		Parameters passed from the caller to the command handler.
		/// </param>
		/// <param term='varOut'>
		///		Parameters passed from the command handler to the caller.
		/// </param>
		/// <param term='handled'>
		///		Informs the caller if the command was handled or not.
		/// </param>
		/// <seealso class='Exec' />
		public void Exec(string commandName, EnvDTE.vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
		{
			handled = false;
			if(executeOption == EnvDTE.vsCommandExecOption.vsCommandExecOptionDoDefault)
			{
				if(commandName == "AopDotNetAddIn.Connect.AspectAddin")
				{
					handled = true;
					return;
				}
				else if (commandName=="AopDotNetAddIn.Connect.WeaveAspects")
				{
					handled=true;
					OnWeaveAspects();
					return;
				}
				else if (commandName=="AopDotNetAddIn.Connect.UnWeaveAspects")
				{
					handled=true;
					
					return;
				}
			}
		}
		private void OnWeaveAspects()
		{
			System.Array  prjs=(Array)applicationObject.ActiveSolutionProjects ;//Solution .StartupProjects ).Item (0);
			if (prjs.Length ==0)
				return;
			curProj=(Project)prjs.GetValue (0);
			//			bool b=applicationObject.Solution.IsDirty ;
			/*	if (curProj.IsDirty==true)
				{
					applicationObject.Solution.SolutionBuild.BuildProject(applicationObject.Solution .SolutionBuild .ActiveConfiguration .Name , curProj.UniqueName ,true) ;
				}*/
			try
			{
				InitCodeGenerator();
				StartWeaving();
			}
			catch(Exception er)
			{
				MessageBox .Show (er.Message ,"AopDotNetAddIn");
			}
		}
		
		public void InitCodeGenerator()
		{
			if (curProj.Kind == PrjKind2.prjKindSDECSharpProject ||curProj.Kind == PrjKind.prjKindCSharpProject )
			{
				codeGenerator =new CSharpCodeProvider().CreateGenerator ();
				curLanguage =AopDotNet.Language.CSharp;
			}
			else
				if (curProj.Kind == PrjKind2.prjKindSDEVBProject ||curProj.Kind == PrjKind.prjKindVBProject  )
			{
				codeGenerator  =new VBCodeProvider ().CreateGenerator (); 
				curLanguage =AopDotNet.Language.VB;
			}
			else if (curProj.Kind ==PrjKind2.prjKindVJSharpProject )
			{
				try
				{
					System.Reflection.Assembly asm= Assembly.Load("VJSharpCodeProvider, version=7.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
					Type t= asm.GetType("Microsoft.VJSharp.VJSharpCodeProvider");
					if (t!=null) 
					{
						Object o= Activator.CreateInstance(t);
						MethodInfo m= t.GetMethod("CreateGenerator", BindingFlags.Public| BindingFlags.Instance, null, new Type[] {}, null);
						codeGenerator = (ICodeGenerator) m.Invoke(o, new Object[] {});
						curLanguage =AopDotNet.Language.JSharp;
					}

				}
				catch(Exception e)
				{
					throw new ArgumentNullException ("Code Provider","AopDotNet Can't be used with this project");
				}
				
			}
		}

		void StartWeaving()
		{
			IsWeaving=true;
			if (! applicationObject.UndoContext.IsOpen )
			{
				applicationObject.UndoContext.Open ("WeavingCheckPoint",true);
		
			}
			ProjectItem aspectDescFile;
			try
			 {
				aspectDescFile=curProj.ProjectItems .Item ("aspectDescriptor.xml");
				if (aspectDescFile==null)
				{
					MessageBox.Show ("aspectDescriptor.xml is not found in the Project","AopDotNetAddIn");
					return;
				}
			}
			catch(Exception exx)
			{
				MessageBox.Show ("aspectDescriptor.xml is not found in the Project","AopDotNetAddIn");
				return;
			
			}
			EditingMonitor editingMonitor=new EditingMonitor (curLanguage);
			XmlCodeModel=new CodeModelBuilder (codeGenerator,editingMonitor);
			CodeElements elms=curProj.CodeModel .CodeElements ;
			XmlCodeModel.BuildTreeFromCodeElements (elms);

			XmlTextWriter writer=new XmlTextWriter("c:\\CodeModel.xml",null);	
			XmlCodeModel.GetXmlDocument ().WriteTo (writer);
			writer.Flush();
			writer.Close ();

			theSearchEngine=new JPSearchEngine (XmlCodeModel,codeGenerator,editingMonitor  );
			theSearchEngine.StartSearch (aspectDescFile.get_FileNames (0));

			/*writer=new XmlTextWriter("c:\\advisedCodeModel.xml",null);	
			XmlCodeModel.GetXmlDocument ().WriteTo (writer);
			writer.Flush();
			writer.Close ();*/

			theWeaver=new Weaver(codeGenerator,curLanguage,curProj,editingMonitor );
			theWeaver.Weave (XmlCodeModel,theSearchEngine.markedEditPoints );
			
			
			string projConfigName=curProj.ConfigurationManager.ActiveConfiguration.ConfigurationName;
			//applicationObject.Documents.SaveAll ();

			IEnumerator en= curProj.ProjectItems.GetEnumerator();
			while(en.MoveNext())
			{
				if (((ProjectItem)en.Current).Document!=null)
					((ProjectItem)en.Current).Document.Save("");
			}
			applicationObject.Solution.SolutionBuild.Clean(true);
			this.bAddInBuild=true;
			applicationObject.Solution.SolutionBuild.BuildProject (projConfigName,curProj.UniqueName,true);
			//applicationObject.Solution.SolutionBuild.Run (); //moved to onbuilddone
			
			
			//applicationObject.Documents.SaveAll ();
			/*if(lastBuildSuccess)
			{
			applicationObject.Solution.SolutionBuild.Run ();
				lastBuildSuccess=false;
			}*/
		}

		
		private _DTE applicationObject;
		private AddIn addInInstance;
		private ICodeGenerator codeGenerator;
		//private ICodeGenerator codeGenerator;
		private CodeModelBuilder XmlCodeModel;
		private AopDotNet.Language  curLanguage ;
		private JPSearchEngine theSearchEngine;
		private Weaver theWeaver;
		private Project curProj;
		private bool IsWeaving;
		private bool bAddInBuild;
		private EnvDTE.SolutionEvents solutionEvents ;
		private BuildEvents buildEvents ;
		public void Execute(object application, int hwndOwner, ref object[] contextParams, ref object[] customParams, ref EnvDTE.wizardResult retval)
		{
			DTE VS=(DTE)application;
			Projects prjs=(Projects)VS.Solution .Projects   ;
			
			Project curProj=null;
			string Name=(string)contextParams[1];
			IEnumerator en=prjs.GetEnumerator ();
			while (en.MoveNext ())
			{
				Project p=(Project)en.Current ;
				if (p.Name ==Name)
					curProj=(Project)en.Current ;
			}
					
			TextRanges textRanges = null;
			ProjectItem projectItemAsp=null;
			
			string projItemsPath=VS.Solution .ProjectItemsTemplatePath (curProj.Kind );
			switch (curProj.Kind )
			{
				case PrjKind.prjKindCSharpProject:
					projItemsPath=projItemsPath+@"\LocalProjectItems\templates\";
					projectItemAsp = curProj.ProjectItems .AddFromTemplate(projItemsPath+ "aspecttemplate.cs", (string)contextParams[4] + ".cs");
					break;
				
				case PrjKind.prjKindVBProject :
					projItemsPath=projItemsPath+@"\Local Project Items\templates\";
					projectItemAsp = curProj.ProjectItems .AddFromTemplate(projItemsPath+ "aspecttemplate.vb", (string)contextParams[4] + ".vb");
					break;
				case PrjKind2.prjKindVJSharpProject:
					projItemsPath=projItemsPath+@"\localprojectitems\templates\";
					projectItemAsp = curProj.ProjectItems .AddFromTemplate(projItemsPath+ "aspecttemplate.jsl", (string)contextParams[4] + ".jsl");
					break;
			}
			try
			{
				ProjectItem aspectDescFile=curProj.ProjectItems.Item ("aspectDescriptor.xml");
				if (aspectDescFile==null)
				{
					curProj.ProjectItems .AddFromTemplate(projItemsPath+ "aspectDescriptor.xml","aspectDescriptor.xml");
				}
			}
			catch(Exception exx)
			{
				curProj.ProjectItems .AddFromTemplate(projItemsPath + "aspectDescriptor.xml","aspectDescriptor.xml");
			}


			Window aspWindow = projectItemAsp.Open(Constants.vsViewKindCode);
			TextDocument aspTextDocument = (TextDocument)aspWindow.Document.Object("TextDocument");
			aspTextDocument.ReplacePattern("%CLASS%", (string)contextParams[4], (int)vsFindOptions.vsFindOptionsNone, ref textRanges);
			string DefaultNamespace=curProj.Properties .Item ("DefaultNamespace").Value .ToString ();
			aspTextDocument.ReplacePattern("%NAMESPACE%",DefaultNamespace, (int)vsFindOptions.vsFindOptionsNone, ref textRanges);
			projectItemAsp.Open (Constants.vsViewKindCode).Visible =true;
			
			
			VSProject VSP=(VSProject)curProj.Object; //specific to C# and VB
			
			if (VSP.References.Find ("AopDotNetAddIn.Connect")!=null)
				return;
			string path=Assembly.GetExecutingAssembly ().Location;
			
			string cha=@"\";
			int index=path.LastIndexOf (@"\");
			if (index!=-1)
			{
				path=path.Substring (0,index);
				cha=@"\";
			}
			else
			{
				index=path.LastIndexOf (@"/");
				if (index!=-1)
				{
					path=path.Substring (0,index);
					cha="/";
				}
			}
						
			/*	UIHierarchy  classview=(UIHierarchy)VS.Windows .Item (Constants.vsWindowKindClassView ).Object ;
				UIHierarchyItem basicnamespace=classview.UIHierarchyItems .Item (0);
				MessageBox.Show (basicnamespace.ToString ());*/

			path=path+cha+"AspectLib.dll";
			VSP.References.Add (path);
		}

		private void buildEvents_OnBuildDone(vsBuildScope Scope, vsBuildAction Action)
		{
			if (bAddInBuild && Action==vsBuildAction.vsBuildActionBuild )
			{
				bAddInBuild =false;
				applicationObject.Solution.SolutionBuild.Run ();
			
				
			}
		}
	}

}